package com.smart.thrift.config.server;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.thread.ThreadUtil;
import com.smart.thrift.discoveryandbalance.discovery.Registry;
import com.smart.thrift.discoveryandbalance.discovery.ThriftServerNode;
import com.smart.thrift.model.common.ThriftServiceSignature;
import com.smart.thrift.model.server.IThriftServer;
import com.smart.thrift.model.wrapper.ThriftServiceWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.SmartLifecycle;
import org.springframework.util.CollectionUtils;

import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class ThriftServerBootstrap implements SmartLifecycle {

    private final ThriftServerGroup thriftServerGroup;

    public ThriftServerBootstrap(ThriftServerGroup thriftServerGroup) {
        this.thriftServerGroup = thriftServerGroup;
    }

    @Override
    public boolean isAutoStartup() {
        return true;
    }

    @Override
    public void start() {
        if (CollectionUtils.isEmpty(thriftServerGroup.getServers())) {
            return;
        }
        log.info("Starting thrift servers");
        AtomicInteger serverIndex = new AtomicInteger(0);
        thriftServerGroup.getServers().forEach(server -> {
            ThriftRunner runner = new ThriftRunner(server);
            new Thread(runner, "thrift-server-" + server.getServerName() + "-" + server.getServerId()).start();
            new Thread(() -> {
                for (int i = 0; i < 5; i++) {
                    boolean serving = server.isServing();
                    if (!serving) {
                        log.info("Waiting thrift server starting");
                    }
                    ThreadUtil.sleep(1000);
                }
                if (server.isServing()) {
                    Registry<?> registry = server.getRegistry();
                    if (registry != null) {
                        ThriftServerNode thriftServerNode = server.getThriftServerNode();
                        for (ThriftServiceWrapper serviceWrapper : server.getServiceWrappers()) {
                            ThriftServiceSignature thriftServiceSignature = serviceWrapper.getThriftServiceSignature();
                            for (String marker : thriftServiceSignature.markersByServiceClass()) {
                                try {
                                    registry.register(marker, server.getServerId(), thriftServerNode);
                                } catch (Exception e) {
                                    log.error("thrift server registry failed", e);
                                }
                            }
                        }
                    }
                }
            }, "thrift-server-" + thriftServerGroup.getServerName() + "-" + serverIndex.incrementAndGet()).start();
        });
    }

    @Override
    public void stop() {
        TimeInterval timer = DateUtil.timer();
        if (isRunning()) {
            log.info("Shutting down thrift servers");
            for (IThriftServer server : thriftServerGroup.getServers()) {
                Registry<?> registry = server.getRegistry();
                if (registry == null) {
                    continue;
                }
                for (ThriftServiceWrapper serviceWrapper : server.getServiceWrappers()) {
                    ThriftServiceSignature thriftServiceSignature = serviceWrapper.getThriftServiceSignature();
                    for (String marker : thriftServiceSignature.markersByServiceClass()) {
                        try {
                            registry.unregister(marker, server.getServerId());
                        } catch (Exception e) {
                            log.error("thrift server registry failed", e);
                        }
                    }
                }
                try {
                    server.shutDown();
                } catch (Exception e) {
                    log.error("server " + server.getServerId() + " stop exception", e);
                }
            }
        }
        log.info("Shut down thrift servers use");
    }

    @Override
    public boolean isRunning() {
        return thriftServerGroup.getServers().stream().anyMatch(IThriftServer::isServing);
    }

    @Override
    public int getPhase() {
        return Integer.MAX_VALUE;
    }

    @Slf4j
    private static class ThriftRunner implements Runnable {
        private final IThriftServer server;

        public ThriftRunner(IThriftServer server) {
            this.server = server;
        }

        @Override
        public void run() {
            log.info("Starting thrift server");
            if (server != null) {
                try {
                    this.server.startUp();
                } catch (Exception e) {
                    log.error("Thrift server failed to start", e);
                }
            }
        }
    }
}
